// ../cms-js-internal/dist/island-runtime/island-runtime.js
var onVisible = (islandEl, callback) => {
  const observer = new IntersectionObserver((entries) => {
    if (entries.some((entry) => entry.isIntersecting)) {
      observer.disconnect();
      callback();
    }
    return;
  });
  for (let i = 0; i < islandEl.children.length; i++) {
    const child = islandEl.children[i];
    observer.observe(child);
  }
};
var MAX_HOSTNAME_LENGTH = 255;
var VALID_HOSTNAME_PATTERN = /^[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
var FORBIDDEN_HOSTNAME_CHARS = /[/?#@:&=+$,[\]<>%\s"'`\\]/;
var INVALID_SUBSTRINGS = [
  "://",
  "?",
  "#",
  ";",
  "\\",
  "..",
  "//",
  // eslint-disable-next-line no-script-url
  "javascript:",
  "data:",
  "vbscript:",
  "<script",
  "base64",
  "alert(",
  "eval(",
  "Function("
];
function isValidHostname(hostname) {
  const isLengthOutOfRange = hostname.length < 1 || hostname.length > MAX_HOSTNAME_LENGTH;
  if (!hostname || typeof hostname !== "string" || isLengthOutOfRange || !hostname.includes(".") || FORBIDDEN_HOSTNAME_CHARS.test(hostname) || !VALID_HOSTNAME_PATTERN.test(hostname) || INVALID_SUBSTRINGS.some(
    (sub) => hostname.toLowerCase().includes(sub.toLowerCase())
  ) || /^[0-9.]+$/.test(hostname)) {
    return false;
  }
  return hostname.split(".").every(
    (label) => label.length >= 1 && label.length <= 63 && !label.startsWith("-") && !label.endsWith("-")
  );
}
function getSecureOverrideUrl(path) {
  const currentUrl = new URL(window.location.toString());
  const overrideHost = currentUrl.searchParams.get("hsDebugOverridePublicHost");
  try {
    if (!overrideHost) {
      throw new Error("No override host provided");
    }
    if (!isValidHostname(overrideHost)) {
      throw new Error("Invalid hostname format");
    }
    const overriddenUrl = new URL(
      `${currentUrl.protocol}//${overrideHost}${path}`
    );
    if (!["http:", "https:"].includes(overriddenUrl.protocol)) {
      throw new Error("Invalid protocol");
    }
    return overriddenUrl.toString();
  } catch (e) {
    console.warn(`Invalid debug override host: ${overrideHost}`, e);
    return `${window.location.origin}${path}`;
  }
}
var rootsToProcess;
var hydrationQueue = [];
var hydrationTypesToAccept = /* @__PURE__ */ new Set(["load", "visible"]);
var startHydratingIdleRootsTimeout;
var shouldForceSeparateJsForAllIslands = /(&|\?)forceSeparateIslandJs=true/.test(window.location.search);
var scheduledHydrationIndexCtr = 1;
var rootsById = /* @__PURE__ */ new Map();
var typedWindow = window;
var startHydratingIdleRoots = () => {
  hydrationTypesToAccept.add("idle");
  for (const root of rootsToProcess) {
    if (root.hydrationStatus === "HYDRATION_WAITING" && hydrationTypesToAccept.has(root.hydrateOn)) {
      root.hydrationStatus = "HYDRATION_PREPARING";
      waitThenLoadAndHydrateIfNeeded(
        root,
        getLoadableModuleFor(root),
        root.wrapperUrl ? getLoadableModuleFor({
          url: root.wrapperUrl,
          id: `${root.id}-wrapper`,
          moduleName: `${root.moduleName}-wrapper`
        }) : void 0
      );
    }
  }
};
function setupIdleCallbackIfNeeded() {
  if (!startHydratingIdleRootsTimeout) {
    if (!window.requestIdleCallback) {
      setTimeout(() => {
        startHydratingIdleRoots();
      }, 1);
      return;
    }
    startHydratingIdleRootsTimeout = requestIdleCallback(
      startHydratingIdleRoots,
      { timeout: 5e3 }
    );
  }
}
function finishHydratingRootAndScheduleNext(rootAndExtraInfo) {
  rootAndExtraInfo.root.hydrationStatus = "HYDRATED";
  hydrationQueue = hydrationQueue.filter(
    (x) => x.root.id !== rootAndExtraInfo.root.id
  );
  const hasOtherRootsToHydrate = hydrationQueue.length > 0;
  if (hasOtherRootsToHydrate) {
    setTimeout(() => hydrateRoot(hydrationQueue[0]), 0);
  } else if (!hasOtherRootsToHydrate && !hydrationTypesToAccept.has("idle")) {
    setupIdleCallbackIfNeeded();
  }
}
function hydrateRoot(rootAndExtraInfo) {
  const { rootEl, root, IslandModule, WrapperModule } = rootAndExtraInfo;
  if (window.location.search.includes("hsDebug=")) {
    console.log("Hydrating root", root.id, root.hydrateOn);
  }
  const postHydration = () => {
    finishHydratingRootAndScheduleNext(rootAndExtraInfo);
  };
  const renderableIsland = {
    rootElement: rootEl,
    pageUrl: typedWindow.__hsServerPageUrl,
    basePath: typedWindow.__hsBasePath,
    islands: typedWindow.__islands,
    postHydration,
    island: root,
    WrapperModule: WrapperModule ? WrapperModule.default : void 0,
    index: rootAndExtraInfo.islandScheduledIndex
  };
  const reactRoot = IslandModule.render(renderableIsland);
  rootsById.set(root.id, reactRoot);
}
function pushToHydrationQueue(rootAndExtraInfo) {
  rootAndExtraInfo.root.hydrationStatus = "HYDRATION_QUEUED";
  hydrationQueue.push(rootAndExtraInfo);
  if (hydrationQueue.length === 1) {
    hydrateRoot(rootAndExtraInfo);
  }
}
function loadThenHydrate(root, LoadableIslandModule, LoadableWrapperModule, rootEl, islandScheduledIndex) {
  Promise.all([
    LoadableIslandModule(),
    LoadableWrapperModule ? LoadableWrapperModule() : Promise.resolve()
  ]).then(
    ([IslandModule, WrapperModule]) => {
      pushToHydrationQueue({
        rootEl,
        root,
        IslandModule,
        WrapperModule,
        islandScheduledIndex
      });
    }
  ).catch((error) => {
    console.error(`Failed to load module for island: ${root.id}`);
    console.error(error);
  });
}
function waitThenLoadAndHydrateIfNeeded(root, LoadableIslandModule, LoadableWrapperModule) {
  const rootEl = document.getElementById(root.id);
  const islandScheduledIndex = scheduledHydrationIndexCtr;
  scheduledHydrationIndexCtr += 1;
  if (root.hydrateOn === "visible") {
    onVisible(rootEl, () => {
      loadThenHydrate(
        root,
        LoadableIslandModule,
        LoadableWrapperModule,
        rootEl,
        islandScheduledIndex
      );
    });
  } else {
    loadThenHydrate(
      root,
      LoadableIslandModule,
      LoadableWrapperModule,
      rootEl,
      islandScheduledIndex
    );
  }
}
function getLoadableModuleFor(root) {
  let url = root.url;
  if (root.url.startsWith("/") && !root.url.startsWith("//") && window.location.search.includes("hsDebugOverridePublicHost=")) {
    url = getSecureOverrideUrl(root.url);
  } else if (!root.url.startsWith("https://") && !root.url.startsWith("http://") && !root.url.startsWith("//")) {
    url = `${window.location.origin}${root.url}`;
  }
  if (shouldForceSeparateJsForAllIslands) {
    url = `${root.url}?cacheBust=${Date.now()}-${root.id}`;
  }
  const LoadableIslandModule = () => import(
    /* @vite-ignore */
    url
  );
  if (!LoadableIslandModule) {
    throw new Error(`Missing island component for ${root.moduleName}`);
  }
  return LoadableIslandModule;
}
function hydrateIslandRoots() {
  if (rootsToProcess === void 0) {
    rootsToProcess = typedWindow.__islands;
    if (window.location.search.includes("hsDebug=")) {
      console.log("Starting to hydrate", rootsToProcess);
    }
    if (shouldForceSeparateJsForAllIslands) {
      console.log("  ... forcibly making every island refetch JS");
    }
  }
  let encounteredAnyNonIdleIslands = false;
  for (const root of rootsToProcess) {
    if (!root.hydrationStatus) {
      root.hydrationStatus = root.hydrationStatus || "HYDRATION_WAITING";
      if (hydrationTypesToAccept.has(root.hydrateOn)) {
        encounteredAnyNonIdleIslands = true;
        root.hydrationStatus = "HYDRATION_PREPARING";
        waitThenLoadAndHydrateIfNeeded(
          root,
          getLoadableModuleFor(root),
          root.wrapperUrl ? getLoadableModuleFor({
            url: root.wrapperUrl,
            id: `${root.id}-wrapper`,
            moduleName: `${root.moduleName}-wrapper`
          }) : void 0
        );
      }
    }
  }
  if (rootsToProcess.length > 0 && !encounteredAnyNonIdleIslands) {
    setupIdleCallbackIfNeeded();
  }
}
function setupIslandHydration() {
  if (document.readyState === "interactive" || document.readyState === "complete") {
    hydrateIslandRoots();
  } else {
    window.addEventListener("DOMContentLoaded", hydrateIslandRoots);
  }
}
function unmountIsland(islandId) {
  const islandToUnmount = rootsToProcess.find(
    (island) => island.id === islandId
  );
  if (!islandToUnmount || !rootsById.get(islandId)) {
    throw new Error(`No known island: ${islandId}`);
  }
  const islandIndex = rootsToProcess.indexOf(islandToUnmount);
  const reactRoot = rootsById.get(islandId);
  rootsToProcess.splice(islandIndex, 1);
  rootsById.delete(islandId);
  console.log("Unmounting island:", islandId);
  reactRoot.unmount();
}
export {
  setupIslandHydration,
  unmountIsland
};
